#ifndef ODBC_DETAILS_BUFFER_HPP	
#define ODBC_DETAILS_BUFFER_HPP

#include "odbc/details/number_buffer_base.hpp"
#include "odbc/details/string_buffer.hpp"
#include "odbc/details/date_buffer.hpp"
#include "odbc/details/time_buffer.hpp"

namespace odbc { namespace details
{

/// \brief It manages a memory buffer that is used for binding and/or fetching data for an ODBC statement parameter or 
///		result set column.
/// \details
///		A buffer provides methods that are needed to bind and access the content of the buffer. 
///		\n
///		See odbc::details::buffer_concept class for the description of a buffer concept.
/// \param T the type to be stored in the buffer.
template< class T>
class buffer { };

/// \ingroup odbcpp
/// \private
/// \brief Helper macro, to declare and implement a template specialization class for a number type.
/// \param N the numeric type to be stored in the buffer.
/// \param OID the ODBC type identifier. See odbc::odbc_types.
/// \param SID the SQL type identifier. See odbc::sql_types.
#define NUMBER_BUFFER( N, OID, SID) \
	template<> class buffer< N>: public number_buffer_base<N, OID, SID> \
	{ \
		typedef number_buffer_base<N, OID, SID> base_type; \
	public: \
		buffer( value_type init_value) : base_type( init_value) { } \
		buffer() { } \
	}

NUMBER_BUFFER( bool, odbc_types::odbc_signed_byte, sql_types::sql_tiny_int);
NUMBER_BUFFER( char, odbc_types::odbc_signed_byte, sql_types::sql_tiny_int);
NUMBER_BUFFER( unsigned char, odbc_types::odbc_unsigned_byte, sql_types::sql_tiny_int);
NUMBER_BUFFER( signed char, odbc_types::odbc_signed_byte, sql_types::sql_tiny_int);
NUMBER_BUFFER( signed short, odbc_types::odbc_short, sql_types::sql_small_int);
NUMBER_BUFFER( unsigned short, odbc_types::odbc_unsigned_short, sql_types::sql_small_int);
NUMBER_BUFFER( wchar_t, odbc_types::odbc_unsigned_short, sql_types::sql_small_int);
NUMBER_BUFFER( signed int, odbc_types::odbc_long, sql_types::sql_integer);
NUMBER_BUFFER( unsigned int, odbc_types::odbc_unsigned_long, sql_types::sql_integer);
NUMBER_BUFFER( signed long, odbc_types::odbc_long, sql_types::sql_integer);
NUMBER_BUFFER( unsigned long, odbc_types::odbc_unsigned_long, sql_types::sql_integer);
NUMBER_BUFFER( float, odbc_types::odbc_float, sql_types::sql_float);
NUMBER_BUFFER( double, odbc_types::odbc_double, sql_types::sql_double);

/// \ingroup odbcpp
/// \brief It implements the buffer for strings.
/// \details Since the string is variable in length and the standard string class is not a POD, additional logic is 
///		needed to map the string to the buffer.
template<>
class buffer< std::string>: public string_buffer_base< std::char_traits< char>, std::allocator< char> >
{
	typedef string_buffer_base< std::char_traits< char>, std::allocator< char> > MyBaseT_;

public:
	/// \brief It initializes the buffer.
	/// \param size the size of the buffer.
	buffer( size_type size = 256)
		: MyBaseT_( size)
	{
	}

	/// \brief It initializes the buffer and copies the specified value in it.
	/// \param initial_value the value to be copied in the buffer after initialization.
	/// \param size the size of the buffer.
	buffer( const value_type& initial_value, size_type size)
		: MyBaseT_( initial_value, size)
	{
	}

	/// \brief It initializes the buffer and copies the specified value in it. The size of the buffer will be set to the 
	///		size of the specified value.
	/// \param initial_value the value the buffer should be initialized with.
	buffer( const value_type& initial_value)
		: MyBaseT_( initial_value, initial_value.size())
	{
	}
};


/// \ingroup odbcpp
/// \brief It implements a buffer that can store a date of type boost::gregorian::date.
/// \details Since the date type is not POD, additional logic for mapping the date to the buffer is needed.
template<>
class buffer< boost::gregorian::date>: public date_buffer_base< odbc_types::odbc_date, sql_types::sql_date>
{
	typedef date_buffer_base< odbc_types::odbc_date, sql_types::sql_date> MyBaseT_;
public:
	/// \brief It initializes the buffer and copies the specified value into it.
	/// \param initial_value the value to be copied in the buffer.
	buffer( const value_type& initial_value)
		: MyBaseT_( initial_value)
	{
	}

	/// \brief It initializes the buffer. The content of the buffer is uninitialized.
	buffer()
	{
	}
};


/// \ingroup odbcpp
/// \brief It implements a buffer that can store a date of type boost::posix_time::ptime.
/// \details Since the posix time class is not a POD, additional logic for mapping it to the buffer is needed.
template<>
class buffer< boost::posix_time::ptime>: public time_buffer_base< odbc_types::odbc_date_time, sql_types::sql_date_time>
{
	typedef time_buffer_base< odbc_types::odbc_date_time, sql_types::sql_date_time> MyBaseT_;
public:
	/// \brief It initializes the buffer and copies the specified value into it.
	/// \param initial_value the value to be copied in the buffer.
	buffer( const value_type& initial_value)
		: MyBaseT_( initial_value)
	{
	}

	/// \brief It initializes the buffer. The content of the buffer is uninitialized.
	buffer()
	{
	}
};

} } // namespace details // namespace odbc

// TODO: Support for BLOB
// TODO: Support for wstring

#endif // ODBC_DETAILS_BUFFER_HPP
